#include "keyboard.h"

#include "application/game_application.h"

#include "util/timer.h"				// log
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    

#include <cassert>

using namespace input;


Keyboard&	Keyboard::Instance()
{
	static Keyboard Inst;
	return Inst;
}



bool	Keyboard::IsKeyDown(unsigned int KeyID)
 {
	if (KeyID > BUFFER_SIZE) return false;
	return m_KeyA[KeyID].KeyDown;
 }
 bool	Keyboard::IsKeyPressed(unsigned int KeyID)
 {
	if (KeyID > BUFFER_SIZE) return false;
	return m_KeyA[KeyID].KeyDown && m_KeyA[KeyID].KeyChanged;
 }
 bool	Keyboard::IsKeyReleased(unsigned int KeyID)
 {
	if (KeyID > BUFFER_SIZE) return false;
	return !m_KeyA[KeyID].KeyDown && m_KeyA[KeyID].KeyChanged;
 }

void	Keyboard::OnCharReceived(unsigned int Key)
{
	// filter non-usefull characters
	if (Key < ' ') return;

	for (unsigned int i=0; i<m_Listeners.size(); i++)
	{
		if (m_Listeners[i]->IsEnabled())	
		{
			m_Listeners[i]->CharReceived(Key); 
		}
	}
}

void	Keyboard::OnCharPressed(unsigned int Key)
{
	KEY*	pKey = GetKey(Key);
	if (!pKey) return;
	pKey->KeyChanged = pKey->KeyDown != true;
	pKey->KeyDown = true;

	if (pKey->KeyChanged)
	{
		pKey->TimeStamp = TIMER().Time();
		for (unsigned int i=0; i<m_Listeners.size(); i++)
		{
			if (m_Listeners[i]->IsEnabled())	
			{
				m_Listeners[i]->KeyPressed(pKey); 
			}
		}
	}

}
void	Keyboard::OnCharReleased(unsigned int Key)
{
	KEY*	pKey = GetKey(Key);
	if (!pKey) return;
	pKey->KeyChanged = pKey->KeyDown != false;
	pKey->KeyDown = false;

	if (pKey->KeyChanged)
	{
		pKey->TimeStamp = TIMER().Time();
		for (unsigned int i=0; i<m_Listeners.size(); i++)
		{
			if (m_Listeners[i]->IsEnabled())	
			{
				m_Listeners[i]->KeyReleased(pKey); 
			}
		}
	}
}

Keyboard::KEY*		Keyboard::GetKey(unsigned int ID)
{
	if (ID >= BUFFER_SIZE) return NULL;
	return &m_KeyA[ID];
}


bool	Keyboard::Tick(float dt)
{	
	if (g_pApp->IsInactive()) 
	{
		// mark everything as up
		for (unsigned int i=0; i<BUFFER_SIZE; i++)
		{
			m_KeyA[i].KeyChanged = false;	/// reset all
			m_KeyA[i].KeyDown = false;
		}
		return false;
	}
	// number of listeners
	size_t Count = m_Listeners.size();
	// update for ones that are down
	for (unsigned int i=0; i<BUFFER_SIZE; i++)
	{
		m_KeyA[i].KeyChanged = false;	/// reset all
		if (m_KeyA[i].KeyDown)
		{
			for (size_t j = 0; j<Count; j++)
			{
				KeyboardListener* pListen = m_Listeners[j];
				if (pListen->IsEnabled())
					pListen->KeyDown(&m_KeyA[i]);
			}	
		}
	}
	return true;
}

void Keyboard::AddListener(KeyboardListener* _pListener)
{
	assert(_pListener && "Adding illegal listener!");
	// exists already
	int	Index = GetListenerIndex(_pListener);
	if (Index != -1)
		return;

	m_Listeners.push_back(_pListener);
}

void Keyboard::DropListener(KeyboardListener* _pListener)
{
	// exists already ?
	int	Index = GetListenerIndex(_pListener);
	if (Index == -1)
		return;

	// found it.. drop it
	 m_Listeners.erase(m_Listeners.begin( ) + Index);

/*	 for (int i=0; i<m_Listeners.size(); i++)
	 {
		KeyboardListener* pListen = m_Listeners[i];
		int j = 0;
	 }*/
}

int	Keyboard::GetListenerIndex(KeyboardListener* _pListener)
{
	size_t Size = m_Listeners.size();
	for (size_t i = 0; i<Size; i++)
	{
		if (m_Listeners[i] == _pListener)
			return (int)i;
	}	
	// not found
	return -1;
}


KeyboardListener::KeyboardListener() :
	m_IsEnabled(true)
{
	m_pKeyboard = &Keyboard::Instance();
	if (m_pKeyboard)
		m_pKeyboard->AddListener(this);
}

KeyboardListener::~KeyboardListener()
{
	m_pKeyboard = &Keyboard::Instance();
	if (m_pKeyboard)
		m_pKeyboard->DropListener(this);
}


void	Keyboard::Init()
{
	for (unsigned int i=0; i<BUFFER_SIZE; i++)
	{
		m_KeyA[i].KeyChanged = false;
		m_KeyA[i].KeyDown	= false;
		m_KeyA[i].KeyChanged = 0;
		m_KeyA[i].KeyID = i;

	}
}

void	Keyboard::Shutdown()
{

}

#ifndef _PLATFORM_WIN32

// no implementation for now
bool	Keyboard::GetClipBoard(std::string& Buffer){ return false; };
bool	Keyboard::SetClipBoard(std::string& Buffer){ return false; };
bool	Keyboard::SetClipBoard(std::wstring& Buffer){ return false; };
bool	Keyboard::IsNumLockOn(){ return false; };
bool	Keyboard::IsCtrlDown(){ return false; };
bool	Keyboard::IsShiftDown(){ return false; };
bool	Keyboard::IsAltDown(){ return false; };
bool	Keyboard::IsVKDown(unsigned int VK) { return false; };

#endif // _PLATFORM_WIN32